;; -*- Lisp -*-
;; ---------------------------------------------------------------
;; MiniLisp - Very small lisp interpreter to demonstrate MiniExp.
;; Copyright (c) 2005  Leon Bottou
;;
;; This software is subject to, and may be distributed under, the
;; GNU General Public License, either Version 2 of the license,
;; or (at your option) any later version. The license should have
;; accompanied the software or you may obtain a copy of the license
;; from the Free Software Foundation at http://www.fsf.org .
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;; ---------------------------------------------------------------

;;   Executable <minilisp> loads this file on startup.
;;   It contains a few helpful minilisp functions and macros.

(defvar defun
  (mlambda((name . args) . body)
     (list 'defvar name (list 'lambda args . body)) ) )

(defvar defmacro
  (mlambda((name . args) . body)
     (list 'defvar name (list 'mlambda args . body)) ) )

(defmacro (pretty f)
  (let ((s (if (symbolp f) (list (list quote f)))))
    (list 'let
      (list (list 's (list 'funcdef f . s)))
      (list 'pprint 's 72)
      () ) ) )

(defun (copyrev l)
   (let ((r ()))
     (while l
       (setq r (cons (car l) r))
       (setq l (cdr l)) )
     r ) )

(defun (copy l)
   (reverse (copyrev l)) )

(defun (append . l)
  (setq l (copyrev l))
  (let ((r (car l)))
    (while (consp (setq l (cdr l)))
      (let ((x (copyrev (car l))))
        (while (consp x)
          (let ((y (cdr x)))
            (setq r (rplacd x r))
            (setq x y) ) ) ) )
    r ) )

(defmacro (when cond . body)
   (list 'if cond (list 'progn . body)) )

(let ((sym-to  '|S 0001|)
      (sym-res '|S 0002|) )
  (defmacro (for (v from to) . body)
    (list 'let (list (list v from)
                     (list sym-to to)
                     (list sym-res ()) )
          (list 'while (list <= v sym-to)
                (list 'setq sym-res (list 'progn . body))
                (list 'setq v (list '+ v 1)) )
          sym-res ) ) )

(let ((sym-to  '|S 0001|)
      (sym-res '|S 0002|) )
  (defmacro (mapfor (v from to) . body)
    (list 'let (list (list v from)
                     (list sym-to to)
                     (list sym-res ()) )
          (list 'while (list <= v sym-to)
                (list 'setq sym-res (list 'cons (list 'progn . body) sym-res))
                (list 'setq v (list '+ v 1)) )
          (list 'reverse sym-res) ) ) )

(defmacro (cond . args)
   (let ((a (copyrev args))
         (r ()))
     (while (consp a)
       (setq r (cons 'if (cons (caar a)
           (if (= (length (cdar a)) 1)
              (list (car (cdar a)) r)
              (list (cons 'progn (cdar a)) r) ) )))
       (setq a (cdr a)) )
     r ) )

(defmacro (not n)
  (list 'nullp n) )

(defmacro (and . args)
   (let ((r 't)
         (a (copyrev args)) )
      (while a
        (setq r (list 'if (car a) r))
        (setq a (cdr a)) )
      r ) )

(defmacro (or . args)
   (let ((r ())
         (a (copyrev args))
         (f (mlambda(x . b)
              (list 'let (list (list 's x))
                 (list 'if 's 's . b) ) )) )
     (while a
        (setq r (list f (car a) r))
        (setq a (cdr a)) )
     r ) )

(defun (mapcar f l)
  (let ((r ()))
    (while l
       (setq r (cons (f (car l)) r))
       (setq l (cdr l)) )
    (reverse r) ) )

(defun (1+ x) (+ x 1))

(defun (1- x) (- x 1))

(defun (2* x) (* x 2))

(defun (2/ x) (/ x 2))

(defun (div n d)
  (floor (/ n d)) )

(defun (mod n d)
   (- n (* d (div n d))) )

(defvar set! setq)

(defvar set-car! rplaca)

(defvar set-cdr! rplacd)

(display "MiniLisp, (C) 2005, Leon Bottou.\n"
         "Available under the GNU General Public Licence.\n\n")
